package com.pai4j.user.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import com.alibaba.nacos.shaded.com.google.common.base.Preconditions;
import com.pai4j.common.bean.PAIResponseBean;
import com.pai4j.common.bean.PAIResponseBeanUtil;
import com.pai4j.common.enums.ResponseCodeEnum;
import com.pai4j.common.constants.WebConstant;
import com.pai4j.common.util.MD5Utils;
import com.pai4j.domain.dto.BindWxRequestDTO;
import com.pai4j.domain.dto.UpdatePasswordDTO;
import com.pai4j.domain.vo.ExSaTokenInfo;
import com.pai4j.domain.vo.request.RegisterRequestDTO;
import com.pai4j.domain.vo.request.UpdateUserInfoResquest;
import com.pai4j.domain.vo.request.request.UserRegistryInfoRequestVO;
import com.pai4j.domain.vo.request.request.UserLoginInfoRequestVO;
import com.pai4j.domain.vo.response.UserBaseResponseInfoVO;
import com.pai4j.domain.vo.response.UserBaseResponseVO;
import com.pai4j.log.annotation.OperationLog;
import com.pai4j.remote.sso.OauthServiceClient;
import com.pai4j.remote.user.UserServiceClient;
import com.pai4j.user.service.SlideVerificationService;
import com.pai4j.user.service.UserService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 用户controller
 *
 * @author: CYM-pai
 * @date: 2025/04/16 20:00
 **/

@Slf4j
@RestController
public class UserServiceController implements UserServiceClient {
    @Resource
    private UserService userService;
    @Resource
    private SlideVerificationService slideVerificationService;
    @Autowired
    private OauthServiceClient oauthServiceClient;


    /**
     * 用户微信公众号扫码登录: 后续改造会将统一登录的接口合并到这里，将手机号当成(valiCode)验证码，
     * 在通过密码和滑块移动验证后才会将手机号传入到saToken框架中进行登录操作！
     *
     * @param validCode  前端输入的验证码
     * @author: CYM-pai
     * @date: 2025/04/16 20:07
     **/
    @Override
    @OperationLog(
        module = "用户管理",
        operation = "用户登录",
        description = "用户微信公众号扫码登录",
        recordParams = false,
        ignoreParams = {"validCode"}
    )
    public PAIResponseBean<SaTokenInfo> doLogin(String validCode) {
        try{
            Preconditions.checkArgument(!StringUtils.isBlank(validCode), "验证码不能为空");
            SaTokenInfo tokenInfo = userService.doLogin(validCode);
            return PAIResponseBeanUtil.success(tokenInfo);
        }catch (Exception e){
            log.error("UserController.doLogin.error:{}", e.getMessage(), e);
            return PAIResponseBeanUtil.error(ResponseCodeEnum.ERROR.getCode(), "登录失败");
        }
    }

    /**
     * 统一登录（账号密码 + 滑块验证）
     * 将手机号作为 Sa-Token 的 loginId 进行登录。
     *
     * @author: CYM-pai
     * @date: 2025/09/23 13:55
     */

    @OperationLog(
        module = "用户管理",
        operation = "用户统一登录",
        description = "账号密码 + 滑块验证登录（loginId=mobile）",
        recordParams = true,
        ignoreParams = {"password"}
    )
    public PAIResponseBean<SaTokenInfo> unifiedLogin(@RequestBody UserLoginInfoRequestVO request) {
        try {
            Assert.notNull(request, "登录参数为空！");
            Assert.isTrue(StringUtils.isNotBlank(request.getMobile()), "手机号为空！");
            Assert.isTrue(StringUtils.isNotBlank(request.getPassword()), "密码为空！");
            Assert.isTrue(StringUtils.isNotBlank(request.getSolidTokenId()), "滑块验证失败！");
            // 1. 滑块验证
            slideVerificationService.validateTokenResult(request.getSolidTokenId());
            // 2. 账号密码校验
            UserBaseResponseVO userBase = userService.getUserBaseByMobile(request.getMobile());
            Assert.isTrue(userBase != null, "账号不存在！");
            String inputPwd = MD5Utils.md5(request.getPassword().concat(WebConstant.MD5_SALT));
            Assert.isTrue(StringUtils.equals(inputPwd, userBase.getPassword()), "密码错误！");
            // 3. 校验通过后，调用统一登录入口（此处复用 doLogin，并将手机号当作 valiCode 传入）
            SaTokenInfo tokenInfo = userService.doLogin(request.getMobile());
            // 调用sso服务生成登录授权码
            PAIResponseBean<String> Code = oauthServiceClient.genLoginOauthCode(userBase.getUid());
            String oauthCode = Code.getData();
            ExSaTokenInfo saTokenInfo = new ExSaTokenInfo();
            BeanUtils.copyProperties(saTokenInfo, tokenInfo);
            saTokenInfo.setOauthCode(oauthCode);
            return PAIResponseBeanUtil.success(saTokenInfo);
        } catch (IllegalArgumentException e) {
            log.error("UserController.unifiedLogin.error:{}", e.getMessage(), e);
            return PAIResponseBeanUtil.error(ResponseCodeEnum.ERROR.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("UserController.unifiedLogin.error:{}", e.getMessage(), e);
            return PAIResponseBeanUtil.error(ResponseCodeEnum.ERROR.getCode(), "登录失败");
        }
    }
    
    /**
     *   统一登录用户绑定微信公众号
     *
     * @author: CYM-pai
     * @date: 2025/06/29 15:36
     **/
    @Override
    public  PAIResponseBean<Boolean> bindWx(@RequestBody BindWxRequestDTO request) {
        Boolean update = userService.updateUserBaseInfoByUid(request);
        return PAIResponseBeanUtil.success(update);
    }
    
    /**
     *  微信扫码时的自动用户注册
     *
     * @author: CYM-pai
     * @date: 2025/04/17 10:44
     **/
    @Override
    @OperationLog(
        module = "用户管理",
        operation = "用户注册",
        description = "用户注册新账号",
        recordParams = true,
        ignoreParams = {"password"}
    )
    public PAIResponseBean<Boolean> register(@RequestBody RegisterRequestDTO request) {
        
        boolean registerResult = userService.register(request);
        return PAIResponseBeanUtil.success(registerResult);
    }

    /**
     *  用户注册:手机号+密码
     *
     * @author: CYM-pai
     * @date: 2025/04/17 10:44
     **/
    @Override
    public PAIResponseBean<Boolean> registry(@RequestBody UserRegistryInfoRequestVO request) {
        boolean registerResult = userService.registry(request);
        return PAIResponseBeanUtil.success(registerResult);
    }
    
    /**
     * 获取用户基本信息
     *
     * @author: CYM-pai
     * @date: 2025/04/23 09:25
     **/
    @Override
    public PAIResponseBean<UserBaseResponseInfoVO> getUserBaseInfo(String userId) {
        UserBaseResponseInfoVO userBaseResponseInfoVO = userService.getUserInfoByUserId(userId);
        return PAIResponseBeanUtil.success(userBaseResponseInfoVO);
    }
    
    
    /**
     *  修改用户基本信息
     *
     * @author: CYM-pai
     * @date: 2025/04/25 21:31
     **/
    @Override
    @OperationLog(
        module = "用户管理",
        operation = "更新用户信息",
        description = "修改用户基本信息",
        recordParams = true
    )
    public PAIResponseBean<Boolean> updateUserBaseInfo(@RequestBody UpdateUserInfoResquest updateUserInfoResquest){
        boolean updateResult = userService.updateUserBaseInfo(updateUserInfoResquest);
        return PAIResponseBeanUtil.success(updateResult);
    }
    
    /**
     *  批量获取用户详情缓存，走redis
     *
     * @author: CYM-pai
     * @date: 2025/04/30 18:38
     **/
    
    @Override
    public PAIResponseBean<Map<String, UserBaseResponseInfoVO>> batchGetMap(@RequestBody Set<String> userIds) {
        Map<String, UserBaseResponseInfoVO> map = userService.batchGet(userIds);
        return PAIResponseBeanUtil.success(map);
    }
    
    /**
     *   批量获取用户详情
     *
     * @author: CYM-pai
     * @date: 2025/04/30 18:39
     **/
    @Override
    public PAIResponseBean<List<UserBaseResponseInfoVO>>batchGetList(@RequestBody List<String> userIds) {
        return PAIResponseBeanUtil.success(userService.batchGetUserListInfoFromCache(userIds));
    }
    
    /**
     * 根据账号获取所有订阅者
     *
     * @param relationType 关系类型，用于区分不同的订阅关系
     * @param account      用户账号，用于查询订阅者
     * @return 返回一个包含订阅者账号集合的PAIResponseBean对象
     */
    @Override
    public PAIResponseBean<Set<String>> getAllSubscriberByAccount(Integer relationType, String account) {
        // 调用userService的getAllSubscriberByAccount方法获取订阅者集合，并通过PAIResponseBeanUtil.success封装结果
        return PAIResponseBeanUtil.success(userService.getAllSubscriberByAccount(relationType, account));
    }
    
    /**
     * 检查是否订阅
     *
     * @param relationType 关系类型，用于区分不同的订阅关系
     * @param userAccount  用户账号，用于检查订阅状态
     * @param account      被订阅的账号
     * @return 返回一个包含布尔值的PAIResponseBean对象，表示是否订阅成功
     */
    @Override
    public PAIResponseBean<Boolean> isSubscribe(Integer relationType, String userAccount, String account) {
        // 调用userService的isSubscribe方法检查订阅状态，并通过PAIResponseBeanUtil.success封装结果
        return PAIResponseBeanUtil.success(userService.isSubscribe(relationType, userAccount, account));
    }
    
    
    /**
     * 根据用户名获取用户基本信息
     *
     * @param name 用户名
     * @return 包含用户基本信息的PAIResponseBean对象
     */
    @Override
    public PAIResponseBean<UserBaseResponseVO> userNameBaseInfo(String name) {
        
        return PAIResponseBeanUtil.success(userService.getUserBaseInfoByUserName(name));
    }
    
    @Override
    public PAIResponseBean<UserBaseResponseVO> userBaseInfo(String mobile) {
        return PAIResponseBeanUtil.success(userService.getUserBaseByMobile(mobile));
    }
    

    
    @Override
    public PAIResponseBean<UserBaseResponseInfoVO> getUserBaseInfoByUid(String uid) {
        UserBaseResponseInfoVO userBaseResponseInfoVO = userService.getUserInfoByUid(uid);
        return PAIResponseBeanUtil.success(userBaseResponseInfoVO);
    }
    
    /**
     *  修改密码
     *
     * @author: CYM-pai
     * @date: 2025/06/30 09:17
     **/
    @Override
    @OperationLog(
        module = "用户管理",
        operation = "修改密码",
        description = "用户修改登录密码",
        recordParams = false,
        ignoreParams = {"oldPassword", "newPassword", "confirmPassword"}
    )
    public PAIResponseBean<Boolean> updatePassword(@RequestBody UpdatePasswordDTO request) {
        Assert.isTrue(request != null, "登录参数为空！");
        String solidTokenId = request.getSolidTokenId();
        Assert.isTrue(StringUtils.isNotBlank(request.getOldPassword()), "旧密码为空！");
        Assert.isTrue(StringUtils.isNotBlank(request.getNewPassword()), "新密码为空！");
        Assert.isTrue(StringUtils.equals(request.getNewPassword(), request.getConfirmPassword()), "2次输入的密码不一致！");
        Assert.isTrue(StringUtils.isNotBlank(solidTokenId), "滑块验证失败！");
        // 滑块验证
        slideVerificationService.validateTokenResult(solidTokenId);
        boolean updateResult = userService.updatePassword(request);
        return PAIResponseBeanUtil.success(updateResult);
    }



    /**
     *  获取用户注册时间
     *
     * @author: CYM-pai
     * @date: 2025/08/11 09:17
     **/
    @Override
    @OperationLog(
            module = "用户管理",
            operation = "获取用户注册时间",
            description = "获取用户注册时间",
            recordParams = false
    )
    public PAIResponseBean<String> getRegisterTime(@PathVariable("userId") String userId) {
           String registerTime = userService.getRegisterTime(userId);
           return PAIResponseBeanUtil.success(registerTime);
    }

    /**
     * 混合搜索用户信息 - 支持用户名（昵称）、手机号、uid三种方式搜索
     *
     * @param searchValue 搜索值（用户名/手机号/uid）
     * @return 用户基础信息
     * @author: CYM-pai
     * @date: 2025/08/22 21:30
     **/
    @Override
    @OperationLog(
            module = "用户管理",
            operation = "混合搜索用户",
            description = "通过用户名、手机号或uid,paiId搜索用户信息",
            recordParams = true
    )
    public PAIResponseBean<UserBaseResponseInfoVO> hybridSearch(@PathVariable("searchValue") String searchValue) {
        try {
            Assert.isTrue(StringUtils.isNotBlank(searchValue), "搜索值不能为空");
            UserBaseResponseInfoVO userInfo = userService.hybridSearch(searchValue);
            return PAIResponseBeanUtil.success(userInfo);
        } catch (Exception e) {
            log.error("UserController.hybridSearch.error:{}", e.getMessage(), e);
            return PAIResponseBeanUtil.error(ResponseCodeEnum.ERROR.getCode(), "搜索失败");
        }
    }
    
    
}
